package logic

import (
	"gddgame.cc/galaxy/asteroid"
	"gddgame.cc/galaxy/asteroid/cluster"
)

type NodeHandler func(node cluster.Node)
type ClientHandler func(client *cluster.Client)

// 提供可挂载的Balance服务
type System interface {
	Node() string
	Client() *cluster.Client
	IsMaster() bool
	StartUp()
	OnStarted(f asteroid.FinishHandler)
	OnFinish(f asteroid.FinishHandler)

	AddMasterListen(f NodeHandler)
	MountNode(f NodeHandler)
	MountClient(f ClientHandler)
	UnMountNode(f NodeHandler)
	UnMountClient(f ClientHandler)

	Alloc(key string) string
}

type system struct {
	region      *asteroid.Region
	container   cluster.Container
	isMaster    bool
	running     bool
	firstFinish bool

	mountNodeFunc     []NodeHandler
	unmountNodeFunc   []NodeHandler
	mountClientFunc   []ClientHandler
	unmountClientFunc []ClientHandler
	masterListenFunc  []NodeHandler

	startedFunc []asteroid.FinishHandler
	finishFunc  []asteroid.FinishHandler

	client *cluster.Client

	node cluster.Node
}

func NewSystem(region *asteroid.Region, engine cluster.Engine) *system {
	s := &system{
		region:      region,
		isMaster:    false,
		running:     false,
		firstFinish: false,
	}
	s.mountNodeFunc = make([]NodeHandler, 0)
	s.unmountNodeFunc = make([]NodeHandler, 0)
	s.mountClientFunc = make([]ClientHandler, 0)
	s.unmountClientFunc = make([]ClientHandler, 0)
	s.masterListenFunc = make([]NodeHandler, 0)

	s.startedFunc = make([]asteroid.FinishHandler, 0)
	s.finishFunc = make([]asteroid.FinishHandler, 0)
	//fmt.Println("system", region.ID(), "register")
	region.OnFinish(func() {
		//fmt.Println("system", region.ID(), "onfinish")
		if !s.firstFinish {
			s.container = engine.Register(region.ID()+".system", region)
			s.firstFinish = true
			engine.RegisterBalance(s)
			//fmt.Println("system", region.ID(), "starting")
			for key, _ := range s.startedFunc {
				s.startedFunc[key]()
			}
		}
		if s.client != nil {
			for key, _ := range s.finishFunc {
				s.finishFunc[key]()
			}
		}
	})

	return s
}

func (s *system) ID() string {
	return s.container.ID()
}

func (s *system) Node() string {
	return s.region.CurrentNode()
}

func (s *system) Client() *cluster.Client {
	return s.client
}
func (s *system) IsMaster() bool {
	return s.isMaster
}

func (s *system) StartUp() {
	s.OnStarted(func() {
		//fmt.Println("system", "started")
		s.container.OnReady(func() {
			//fmt.Println("onReady", s.ID())
			s.client = s.container.Balance().GenerateClient(s.ID(), "")
			s.running = true
			// 首次finish时为完成client注册，在初始化时直接处理
			for key, _ := range s.finishFunc {
				s.finishFunc[key]()
			}
			if s.node != nil {
				for key, _ := range s.mountNodeFunc {
					s.mountNodeFunc[key](s.node)
				}
				if s.isMaster {
					for k, _ := range s.masterListenFunc {
						s.masterListenFunc[k](s.node)
					}
				}
			}

		})
	})
}

// region准备完成
func (s *system) OnStarted(f asteroid.FinishHandler) {
	//fmt.Println("on started", s.firstFinish)
	s.startedFunc = append(s.startedFunc, f)
	if s.firstFinish {
		f()
	}
}

// region节点更新完成
func (s *system) OnFinish(f asteroid.FinishHandler) {
	s.finishFunc = append(s.finishFunc, f)
	if s.firstFinish && s.client != nil {
		f()
	}
}
func (s *system) AddMasterListen(f NodeHandler) {
	s.masterListenFunc = append(s.masterListenFunc, f)
	if s.running && s.isMaster {
		f(s.node)
	}
}

func (s *system) MountNode(f NodeHandler) {
	s.mountNodeFunc = append(s.mountNodeFunc, f)
	if s.running && s.node != nil {
		f(s.node)
	}
}

func (s *system) MountClient(f ClientHandler) {
	s.mountClientFunc = append(s.mountClientFunc, f)
	if s.running && s.client != nil {
		f(s.client)
	}
}

func (s *system) UnMountNode(f NodeHandler) {
	s.unmountNodeFunc = append(s.unmountNodeFunc, f)
}

func (s *system) UnMountClient(f ClientHandler) {
	s.unmountClientFunc = append(s.unmountClientFunc, f)
}

func (s *system) Init(node cluster.Node) {
	//fmt.Println("onInit", s.ID())
	node.SetConfig(cluster.Simple, true)
	s.node = node
	if s.running {
		for key, _ := range s.mountNodeFunc {
			s.mountNodeFunc[key](node)
		}
	}
}

func (s *system) InitClient(client *cluster.Client) {
	//fmt.Println("onInitClient", s.ID())
	for key, _ := range s.mountClientFunc {
		s.mountClientFunc[key](client)
	}
}

func (s *system) CloseInstance(node cluster.Node) {
	for key, _ := range s.unmountNodeFunc {
		s.unmountNodeFunc[key](node)
	}
}

func (s *system) CloseClient(client *cluster.Client) {
	for key, _ := range s.unmountClientFunc {
		s.unmountClientFunc[key](client)
	}
}

func (s *system) Master(node cluster.Node) {
	s.isMaster = true
	if s.running {
		for k, _ := range s.masterListenFunc {
			s.masterListenFunc[k](node)
		}
	}
}

func (s *system) Alloc(key string) string {
	return s.region.Alloc(key)
}
